package com.hsc.www.redis.jedisLettuce.jedis;

import com.alibaba.fastjson.JSONObject;
import org.junit.Test;

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;

public class Main {


    public static void sleep(int seconds) {
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void test1() throws Exception {
        //无返会值
        Runnable runnable = () -> {
            System.out.println("runnable");
        };
        CompletableFuture future1 = CompletableFuture.runAsync(runnable);
        System.out.println("future1=" + future1.get());

        //有返回值
        Supplier<String> supplier = () -> {
            System.out.println("supplier");
            return "supplier";
        };
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(supplier);
        System.out.println("future2=" + future2.get());

        sleep(100);
    }


    @Test
    public void test8() throws Exception {

        Supplier<String> supplier = () -> {
            return Thread.currentThread().getName();
        };
        //使用默认线程池
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(supplier);
        System.out.println("future1=" + future1.get());

        //使用自定义线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(supplier, threadPool);
        System.out.println("future2=" + future2.get());

        sleep(100);
        threadPool.shutdown();
    }


    @Test
    public void test9() throws Exception {
        System.out.println("本方法所用线程 " + Thread.currentThread().getName());
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        //一个5秒任务
        Supplier<String> supplier = () -> {
            sleep(5);
            int i=1/0;

            String s = "supplier " + Thread.currentThread().getName();
            System.out.println(s);
            return s;
        };
        //任务完成后的行为
        BiConsumer<Object, Throwable> action = (result, exception) -> {
            String s = "action " + Thread.currentThread().getName();
            System.out.println(s);
        };

        //将任务交给线程池处理,任务结束会自动调用CompletableFuture.complete()方法。
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(supplier, threadPool);
        //睡1秒，这时任务还没结束，这时调用whenComplete方法，将会和supplier的执行使用相同的线程。
        sleep(1);
        CompletableFuture future2 = future1.whenComplete(action);

        //睡10秒，这时任务已结束，这时调用whenComplete方法。只能使用调用本方法的线程
        sleep(10);
        CompletableFuture future3 = future1.whenComplete(action);

        sleep(100);
    }

    @Test
    public void test10() throws Exception {
        System.out.println("本方法所用线程 " + Thread.currentThread().getName());
        //一个5秒任务
        Supplier<Integer> supplier = () -> {
            sleep(5);
            String s = "supplier " + Thread.currentThread().getName();
            int i=1/0;

            System.out.println(s);
            return 5;
        };

        //一个后继任务
        Function<Integer,String> function = (result) -> {
            String s = "function " + Thread.currentThread().getName();
            System.out.println(s);
            return "结果是："+result;
        };

        //将任务交给线程池处理
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(supplier);
        //睡1秒
        sleep(1);
        CompletableFuture<String> future2 = future1.thenApply(function);
        System.out.println(future2.get());
        //睡10秒
        sleep(10);
        CompletableFuture<String> future3 = future1.thenApply(function);
        System.out.println(future3.get());

        sleep(100);
    }


    @Test
    public void test11() throws Exception {
        System.out.println("本方法所用线程 " + Thread.currentThread().getName());
        //一个5秒任务
        Supplier<Integer> supplier = () -> {
            sleep(5);
            String s = "supplier " + Thread.currentThread().getName();
            int i=1/0;

            System.out.println(s);
            return 5;
        };

        //一个后继任务
        Function<Integer,String> function = (result) -> {
            String s = "function " + Thread.currentThread().getName();
            System.out.println(s);
            return "结果是："+result;
        };

        //将任务交给线程池处理
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(supplier);
        //睡1秒
        sleep(1);
        CompletableFuture<String> future2 = future1.thenApply(function);
        System.out.println(future2.get());
        //睡10秒
        sleep(10);
        CompletableFuture<String> future3 = future1.thenApply(function);
        System.out.println(future3.get());

        sleep(100);
    }

    @Test
    public void test4() throws Exception {

        ExecutorService threadPool = Executors.newFixedThreadPool(3);

        Runnable runnable = () -> {
            String s = "runnable " + Thread.currentThread().getName();
            System.out.println(s);
        };


        Supplier<String> supplier = () -> {
            String s = "supplier " + Thread.currentThread().getName();
            System.out.println(s);
            return s;
        };

        CompletableFuture future1 = CompletableFuture.runAsync(runnable, threadPool);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(supplier, threadPool);

        BiConsumer<Object, Throwable> action = (result, exception) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("result", result);
            map.put("exception", exception);
            map.put("threadName", Thread.currentThread().getName());
            System.out.println(JSONObject.toJSONString(map));
        };


        CompletableFuture future11 = future1.whenComplete(action);
        CompletableFuture future21 = future2.whenCompleteAsync(action);
        CompletableFuture future111 = future11.whenCompleteAsync(action);
        CompletableFuture future211 = future21.whenComplete(action);


        System.out.println("future1=" + future1.get());
        System.out.println("future2=" + future2.get());
        threadPool.shutdown();
        sleep(10);
    }


    @Test
    public void test5() throws Exception {

        Supplier<String> supplier = () -> {
            sleep(0);
            return "supplier";
        };
        CompletableFuture<String> future = CompletableFuture.supplyAsync(supplier);

        BiConsumer<Object, Throwable> action = (result, exception) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("result", result);
            map.put("exception", exception);
            map.put("threadName", Thread.currentThread().getName());
            sleep(2);
            System.out.println(JSONObject.toJSONString(map));

        };


        CompletableFuture future1 = future.whenComplete(action);
        System.out.println("future1");

        CompletableFuture future2 = future.whenComplete(action);
        System.out.println("future2");

//        CompletableFuture future3 = future.whenCompleteAsync(action);
//        System.out.println("future3");
//
//        CompletableFuture future4 = future.whenCompleteAsync(action);
//        System.out.println("future4");

        sleep(100);


    }


    @Test
    public void test() throws Exception {

        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        Callable<String> callable = () -> {
            return exec(5);
        };
        final Future<String> future1 = threadPool.submit(callable);


        Supplier<String> supplier = () -> {
            return exec(5);
        };
        final CompletableFuture<String> future2 = CompletableFuture.supplyAsync(supplier);
        final CompletableFuture<String> future3 = CompletableFuture.supplyAsync(supplier, threadPool);


        System.out.println("future1=" + future1.get());
        System.out.println("future2=" + future2.get());
        System.out.println("future3=" + future3.get());
        threadPool.shutdown();
        while (true) ;
    }

    public static String exec(int seconds) {
        Thread currentThread = Thread.currentThread();
        String s = "ThreadName:" + currentThread.getName() + " isDaemon:" + currentThread.isDaemon();
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return s;
    }


    @Test
    public void test2() throws Exception {

        Supplier<String> supplier1 = () -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (Exception e) {
            }
            return "one";
        };
        Supplier<String> supplier2 = () -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (Exception e) {
            }
            return "two";
        };
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(supplier1);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(supplier2);
        CompletableFuture future = CompletableFuture.allOf(future1, future2);
        System.out.println("allOf=" + future.get());

        future1 = CompletableFuture.supplyAsync(supplier1);
        future2 = CompletableFuture.supplyAsync(supplier2);
        future = CompletableFuture.anyOf(future1, future2);
        System.out.println("anyOf=" + future.get());
    }

    @Test
    public void test3() throws Exception {

        Supplier<String> supplier1 = () -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (Exception e) {
            }
            return "one";
        };

        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(supplier1);


    }

    public static synchronized void writeToFile(String s) {
        try {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            String path = classLoader.getResource("abc.log").getFile();
            Writer writer = new FileWriter(new File(path), true);
            writer.append("\r\n" + new Date().toString() + "  ");
            writer.append(s);
            writer.flush();
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
